<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Centos7 编译安装 Python 3.9.0">
<meta name="twitter:description" content="<p>在Centos7系统上，从源码编译安装Python 3.9.0：编译中遇到的坑，依赖项的解决，安装后一直到别的服务器</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/compile-python-from-source.html"/>
<meta property="og:title" content="来玩魔王的咚 | Centos7 编译安装 Python 3.9.0" />
<meta property="og:description" content="<p>在Centos7系统上，从源码编译安装Python 3.9.0：编译中遇到的坑，依赖项的解决，安装后一直到别的服务器</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>在Centos7系统上，从源码编译安装Python 3.9.0：编译中遇到的坑，依赖项的解决，安装后一直到别的服务器</p>" />

    <meta name="tags" content="python" />
    <meta name="tags" content="make" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li class="active"><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-10-13 11:00:00+08:00">
                <script>document.write(moment('2020-10-13 11:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-10-13 11:00:00+08:00">
                <script>document.write(moment('2020-10-15 16:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Centos7 编译安装 Python 3.9.0
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#xia-zai-yuan-ma-wen-jian">下载源码文件</a><ul>
<li><a href="#readme-wen-jian">README 文件</a></li>
<li><a href="#an-zhuang-ji-ben-yi-lai-xiang">安装基本依赖项</a></li>
<li><a href="#an-zhuang-wan-zheng-yi-lai-xiang">安装完整依赖项</a></li>
</ul>
</li>
<li><a href="#configure-pei-zhi">configure 配置</a></li>
<li><a href="#make-bian-yi">make 编译</a><ul>
<li><a href="#bian-yi-bao-gao">编译报告</a></li>
<li><a href="#gcc-ban-ben-dao-zhi-bian-yi-cuo-wu">gcc版本导致编译错误</a></li>
</ul>
</li>
<li><a href="#make-test">make test</a></li>
<li><a href="#make-install-an-zhuang">make install 安装</a></li>
<li><a href="#zhu-ge-jie-jue-yi-lai-xiang-wen-ti">逐个解决依赖项问题</a><ul>
<li><a href="#pip-install-bao-cuo">pip install 报错</a></li>
<li><a href="#python-shell-wu-fa-yi-dong-guang-biao">python shell 无法移动光标</a></li>
<li><a href="#que-shao-qi-ta-yi-lai-xiang">缺少其他依赖项</a></li>
</ul>
</li>
<li><a href="#pip-pei-zhi">pip 配置</a></li>
<li><a href="#yi-zhi">移植</a></li>
</ul>
</div>
<p>操作系统版本：</p>
<div class="highlight"><pre><span></span><code>$ cat /etc/redhat-release
CentOS Linux release <span class="m">7</span>.7.1908 <span class="o">(</span>Core<span class="o">)</span>
$ 
</code></pre></div>

<p>Python 3.9.0 信息：Release Date: Oct. 5, 2020  </p>
<h3 id="xia-zai-yuan-ma-wen-jian"><a class="toclink" href="#xia-zai-yuan-ma-wen-jian">下载源码文件</a></h3>
<p>Python官网：<a href="https://www.python.org/">https://www.python.org/</a>  </p>
<p>下载源码文件并解压：</p>
<div class="highlight"><pre><span></span><code>wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
tar -zxvf Python-3.9.0.tgz
</code></pre></div>

<h4 id="readme-wen-jian"><a class="toclink" href="#readme-wen-jian">README 文件</a></h4>
<p>首先，看一下README：</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span> Python-3.9.0
cat README.rst
</code></pre></div>

<p>关于安装步骤：</p>
<div class="highlight"><pre><span></span><code>Build Instructions
------------------

On Unix, Linux, BSD, macOS, and Cygwin::

    ./configure
    make
    make test
    sudo make install

This will install Python as ``python3``.
</code></pre></div>

<p>主要就是上面几个步骤。  </p>
<p>另外，文档后面还提到，构建完整的python需要用到系统提供的一些第三方库。不过，其中大多数都不影响python安装和基本的使用，并且也不是所有的标准库模块是所有系统平台都可用的。<br>
关于依赖项，下面的小节展开。  </p>
<h4 id="an-zhuang-ji-ben-yi-lai-xiang"><a class="toclink" href="#an-zhuang-ji-ben-yi-lai-xiang">安装基本依赖项</a></h4>
<p>这里只讲几个影响安装和基本使用的依赖项。都是已知的，使用时马上就会遇到问题的依赖项。完整依赖项的安装，可以直接跳到下一小节。<br>
下面这些不一定是最全的，但每一个都是必须的：</p>
<div class="highlight"><pre><span></span><code>yum install gcc zlib-devel openssl-devel readline-devel
</code></pre></div>

<p>./configure 的时候需要gcc<br>
make install 的时候需要zlib-devel<br>
python安装成功后要能使用pip安装模块，需要openssl-devel<br>
直接运行python3命令，进入python shell中后，需要readline-devel，否则移动光标会出乱码  </p>
<h4 id="an-zhuang-wan-zheng-yi-lai-xiang"><a class="toclink" href="#an-zhuang-wan-zheng-yi-lai-xiang">安装完整依赖项</a></h4>
<p>在上面的README文档中，有给出参考的链接。安装依赖项：<a href="https://devguide.python.org/setup/#install-dependencies">https://devguide.python.org/setup/#install-dependencies</a><br>
直接按照官方文档给的命令照做就好了：</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install yum-utils
$ sudo yum-builddep python3
</code></pre></div>

<p>首先安装了工具yum-utils，之后可以使用命令yum-builddep。<br>
执行后就是相当于执行了<code>yum installl</code>，这里要安装一堆软件包：</p>
<div class="highlight"><pre><span></span><code>事务概要
========================================================================================================================
安装  30 软件包 (+114 依赖软件包)
升级            (  18 依赖软件包)

总下载量：109 M
Is this ok [y/d/N]:
</code></pre></div>

<h3 id="configure-pei-zhi"><a class="toclink" href="#configure-pei-zhi">configure 配置</a></h3>
<p>查看帮助说明：</p>
<div class="highlight"><pre><span></span><code>$ ./configure -h
......
Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]
......
$ 
</code></pre></div>

<p>有点长，有问题可以参考一下。<br>
常用的参数有<code>--prefix=PREFIX</code>指定安装路径，这里显示默认路径是<code>/usr/local</code>。  </p>
<p>如果没有安装gcc是会报错的：</p>
<div class="highlight"><pre><span></span><code>$ ./configure
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for python3.9... no
checking for python3... no
checking for python... python
checking for --enable-universalsdk... no
checking for --with-universal-archs... no
checking MACHDEP... &quot;linux&quot;
checking for gcc... no
checking for cc... no
checking for cl.exe... no
configure: error: in `/root/Python-3.9.0&#39;:
configure: error: no acceptable C compiler found in $PATH
See `config.log&#39; for more details
$
</code></pre></div>

<p>一般就不带任何参数，直接运行：</p>
<div class="highlight"><pre><span></span><code>$ ./configure
......
creating Modules/Setup.local
creating Makefile


If you want a release build with all stable optimizations active (PGO, etc),
please run ./configure --enable-optimizations


$  
</code></pre></div>

<p>这里最后的提示是建议带<code>--enable-optimizations</code>执行，应该是一个优化选项。  </p>
<p>使用建议的参数再执行一次：</p>
<div class="highlight"><pre><span></span><code>$ ./configure --enable-optimizations
</code></pre></div>

<p>这里遇到了坑，带参数不能直接执行。必须先不带参数执行一遍，然后再加上参数执行一遍。<br>
如果直接带参数执行，下面make的时候会报错，下面单独有一小节展开排错的过程。  </p>
<h3 id="make-bian-yi"><a class="toclink" href="#make-bian-yi">make 编译</a></h3>
<p><strong>make</strong> 命令用于自动编译，这是一个很强大的命令，它用于维护一个大的程序，往往这类程序的源码由许多文件构成。典型的，有一些是 <strong>header files 头文件</strong>，源文件通常使用 <strong>include</strong> 指令包含这些文件，make 的作用就是跟踪哪些文件属于头文件，然后安排自动编译的过程。  </p>
<h4 id="bian-yi-bao-gao"><a class="toclink" href="#bian-yi-bao-gao">编译报告</a></h4>
<p>直接执行make命令，执行完成后，看最后的部分：</p>
<div class="highlight"><pre><span></span><code>$ make
......
Python build finished successfully!
The necessary bits to build these optional modules were not found:
_bz2                  _curses               _curses_panel
_dbm                  _gdbm                 _hashlib
_lzma                 _sqlite3              _ssl
_tkinter              _uuid                 readline
zlib
To find the necessary bits, look in setup.py in detect_modules() for the module&#39;s name.


The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  atexit                pwd
time


Failed to build these modules:
_ctypes


Could not build the ssl module!
Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
LibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381
......
$ 
</code></pre></div>

<p>这次make前，依赖项是都没有安装的。<br>
首先，提示build成功：<code>Python build finished successfully!</code>。<br>
紧接着的是由于缺少依赖项，所以未生成这些扩展模块：_bz2、_curses 等等。<br>
另外ssl模块非常重要，最后又单独给了一个提示。缺少ssl模块会影响pip命令的使用。  </p>
<p>第一次执行make会比较耗时，之后再执行make就快很多。因为已经编译好的文件就会直接跳过，不会重复编译生成新文件。如果需要再完整的重新编译一次，那么在make之前先执行一下make clean。这个在下面的小节，处理<strong>gcc版本导致编译错误</strong>的最后用到了。  </p>
<p>这份编译报告，很有用，上面列出了有哪些问题。之后还需要再看这个确认问题，再要看的时候，就再执行一次make，很快就能执行完毕。这里列出的问题，在之后解决依赖项的时候，基本通过新生成的make报告就能确认依赖问题是否解决了。<br>
虽然提示中列出了编译中的一些问题，但是build是成功的。可以继续安装，所以继续执行<code>make install</code>后就能完成pytho的安装，并且验证程序也是能够执行的。但是缺少的依赖，在用到的时候就会报错。  </p>
<h4 id="gcc-ban-ben-dao-zhi-bian-yi-cuo-wu"><a class="toclink" href="#gcc-ban-ben-dao-zhi-bian-yi-cuo-wu">gcc版本导致编译错误</a></h4>
<p>由于第一次在上午成功执行了完整的安装过程：</p>
<div class="highlight"><pre><span></span><code>./configure
./configure --enable-optimizations
make
make install
</code></pre></div>

<p>当时故意没预先安装很多依赖项。于是下午镜像还原系统后，想先安装好依赖项再跑一遍的时候，遇到了问题。之后尝试完全按照上午的操作步骤再来一遍，依然还是报错。下面是我排错的过程。  </p>
<p>执行make之后，屏幕上输出的最后的部分，这些应该是完整的报错信息了：</p>
<div class="highlight"><pre><span></span><code>$ make
......
Could not import runpy module
Traceback (most recent call last):
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 15, in &lt;module&gt;
    import importlib.util
  File &quot;/root/Python-3.9.0/Lib/importlib/util.py&quot;, line 2, in &lt;module&gt;
    from . import abc
  File &quot;/root/Python-3.9.0/Lib/importlib/abc.py&quot;, line 17, in &lt;module&gt;
    from typing import Protocol, runtime_checkable
  File &quot;/root/Python-3.9.0/Lib/typing.py&quot;, line 21, in &lt;module&gt;
    import collections
SystemError: &lt;built-in function compile&gt; returned NULL without setting an error
generate-posix-vars failed
make[1]: *** [pybuilddir.txt] 错误 1
make[1]: 离开目录“/root/Python-3.9.0”
make: *** [profile-opt] 错误 2
$ 
</code></pre></div>

<p>并没有在网上找到解决的办法。但是有提到gcc的版本问题。<em>（可能是新版本的BUG）</em>  </p>
<p>由于使用的阿里源yum安装的gcc，去查了一个软件包的更新时间，去下面的地址搜了一下：</p>
<div class="highlight"><pre><span></span><code>https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/
gcc-4.8.5-39.el7.x86_64.rpm    22-Aug-2019 21:24    16966352
</code></pre></div>

<p>这个是1年半之前的版本了，所以上午和下午安装的应该是同一个版本的gcc。<br>
这里也没法装一个稍旧的版本试一下，虽然搜到这样的解决办法，并且现在看应该也能解决问题。但是没法使用yum，也没有现成的rpm包，而且还有很多依赖项。只有yum源上这唯一的一个版本可用，并且该版本看着也很稳定。  </p>
<p>由于使用镜像还原的系统，第一次是成功的，之后每一步都有记录，操作上应该没有任何差别。唯一能想到的变化就是yum安装的时候下载的包发生的变化。<br>
第二天，继续上面的思路，转向安装gcc的时候一起安装和升级的依赖项。安装gcc时的依赖关系：</p>
<div class="highlight"><pre><span></span><code>依赖关系解决

========================================================================================================================
 Package                       架构                  版本                                  源                      大小
========================================================================================================================
正在安装:
 gcc                           x86_64                4.8.5-39.el7                          base                    16 M
为依赖而安装:
 cpp                           x86_64                4.8.5-39.el7                          base                   5.9 M
 glibc-devel                   x86_64                2.17-307.el7.1                        base                   1.1 M
 glibc-headers                 x86_64                2.17-307.el7.1                        base                   689 k
 kernel-headers                x86_64                3.10.0-1127.19.1.el7                  updates                9.0 M
 libmpc                        x86_64                1.0.1-3.el7                           base                    51 k
 mpfr                          x86_64                3.1.1-4.el7                           base                   203 k
为依赖而更新:
 glibc                         x86_64                2.17-307.el7.1                        base                   3.6 M
 glibc-common                  x86_64                2.17-307.el7.1                        base                    11 M

事务概要
========================================================================================================================
安装  1 软件包 (+6 依赖软件包)
升级           ( 2 依赖软件包)

总下载量：48 M
</code></pre></div>

<p>再次去阿里源上确认下每个包的版本和更新时间：</p>
<ul>
<li>base源：<a href="https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/">https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/</a></li>
<li>updates源：<a href="https://mirrors.aliyun.com/centos/7/updates/x86_64/Packages/">https://mirrors.aliyun.com/centos/7/updates/x86_64/Packages/</a></li>
</ul>
<p>在updates源的kernel-headers看到了一些可能性：</p>
<div class="highlight"><pre><span></span><code>kernel-headers-3.10.0-1127.10.1.el7.x86_64.rpm     03-Jun-2020 20:34     9382784
kernel-headers-3.10.0-1127.13.1.el7.x86_64.rpm     23-Jun-2020 17:36     9385160
kernel-headers-3.10.0-1127.18.2.el7.x86_64.rpm     29-Jul-2020 22:29     9389504
kernel-headers-3.10.0-1127.19.1.el7.x86_64.rpm     25-Aug-2020 18:25     9389840
kernel-headers-3.10.0-1127.8.2.el7.x86_64.rpm      14-May-2020 08:58     9381264
</code></pre></div>

<p>这个包有多个版本，虽然最新版本也是1个多月之前的事情了，但这次更换版本不是太费事，这次版本有的选，就降级到前一个版本试了下：</p>
<div class="highlight"><pre><span></span><code>$ yum downgrade kernel-headers-3.10.0-1127.18.2.el7
</code></pre></div>

<p>由于make不会重复编译，已经已经完成的部分是有问题的，降级了版本后也不会重复数编译有问题的部分。需要先清除之前编译的结果：</p>
<div class="highlight"><pre><span></span><code>$ make clean
$ make
</code></pre></div>

<p>终于编译又能成功了。  </p>
<p>另外，还查到有文章指出<code>./configure --enable-optimizations</code>，这里添加的选项也会导致这个问题。而我实际的操作步骤是：</p>
<div class="highlight"><pre><span></span><code>./configure
./configure --enable-optimizations
make
yum downgrade kernel-headers-3.10.0-1127.18.2.el7
make clean
make
</code></pre></div>

<p>主要是不带选项先跑了一遍配置，之后看到结果的提示后，再带选项跑了一遍配置。似乎直接执行带选项跑配置也会出现这里的报错。如果遇到问题，试着向这里一样先不带选项跑一遍，再加上选项跑一遍。或者干脆把选项去掉不要加了。  </p>
<p>至此，问题解决。  </p>
<h3 id="make-test"><a class="toclink" href="#make-test">make test</a></h3>
<p>这是一个可选操作，一遍的编译安装没有也不需要这步，并且执行还非常耗时。<br>
这一小节的操作，全部重来一遍，操作步骤如下：</p>
<div class="highlight"><pre><span></span><code>wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
tar -zxvf Python-3.9.0.tgz
<span class="nb">cd</span> Python-3.9.0

yum install yum-utils
yum-builddep python3
yum downgrade kernel-headers-3.10.0-1127.18.2.el7

./configure --prefix<span class="o">=</span>/usr/local/python3.9
./configure --enable-optimizations --prefix<span class="o">=</span>/usr/local/python3.9
make
make <span class="nb">test</span>
make install
</code></pre></div>

<p>这里指定了安装目录，方便后面的移植。  </p>
<p>执行make命令后，完整的输出如下，编译没有任何问题：</p>
<div class="highlight"><pre><span></span><code>$ make
Rebuilding with profile guided optimizations:
rm -f profile-clean-stamp
make build_all CFLAGS_NODIST=&quot; -fprofile-use -fprofile-correction&quot; LDFLAGS_NODIST=&quot;&quot;
make[1]: 进入目录“/root/Python-3.9.0”
 CC=&#39;gcc -pthread&#39; LDSHARED=&#39;gcc -pthread -shared    &#39; OPT=&#39;-DNDEBUG -g -fwrapv -O3 -Wall&#39;      _TCLTK_INCLUDES=&#39;&#39; _TCLTK_LIBS=&#39;&#39;       ./python -E ./setup.py  build
running build
running build_ext

The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  atexit                pwd
time

running build_scripts
copying and adjusting /root/Python-3.9.0/Tools/scripts/pydoc3 -&gt; build/scripts-3.9
copying and adjusting /root/Python-3.9.0/Tools/scripts/idle3 -&gt; build/scripts-3.9
copying and adjusting /root/Python-3.9.0/Tools/scripts/2to3 -&gt; build/scripts-3.9
changing mode of build/scripts-3.9/pydoc3 from 644 to 755
changing mode of build/scripts-3.9/idle3 from 644 to 755
changing mode of build/scripts-3.9/2to3 from 644 to 755
renaming build/scripts-3.9/pydoc3 to build/scripts-3.9/pydoc3.9
renaming build/scripts-3.9/idle3 to build/scripts-3.9/idle3.9
renaming build/scripts-3.9/2to3 to build/scripts-3.9/2to3-3.9
make[1]: 离开目录“/root/Python-3.9.0”
$ 
</code></pre></div>

<p>执行命令后，耗时非常长，输出也很多。全部完成后，最后会有报告：</p>
<div class="highlight"><pre><span></span><code>$ make test
......

== Tests result: SUCCESS ==

410 tests OK.

1 test altered the execution environment:
    test_site

14 tests skipped:
    test_devpoll test_gdb test_ioctl test_kqueue test_msilib
    test_ossaudiodev test_startfile test_tix test_tk test_ttk_guionly
    test_winconsoleio test_winreg test_winsound test_zipfile64

Total duration: 13 min 31 sec
Tests result: SUCCESS
$ 
</code></pre></div>

<h3 id="make-install-an-zhuang"><a class="toclink" href="#make-install-an-zhuang">make install 安装</a></h3>
<p>下面是未安装zlib依赖项时，命令执行到中途出现的报错，并且执行中断：</p>
<div class="highlight"><pre><span></span><code>$ make install
......
Traceback (most recent call last):
  File &quot;&lt;frozen zipimport&gt;&quot;, line 520, in _get_decompress_func
ModuleNotFoundError: No module named &#39;zlib&#39;

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File &quot;&lt;frozen zipimport&gt;&quot;, line 568, in _get_data
  File &quot;&lt;frozen zipimport&gt;&quot;, line 523, in _get_decompress_func
zipimport.ZipImportError: can&#39;t decompress data; zlib not available

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File &quot;&lt;string&gt;&quot;, line 6, in &lt;module&gt;
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 206, in run_module
    mod_name, mod_spec, code = _get_module_details(mod_name)
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 147, in _get_module_details
    return _get_module_details(pkg_main_name, error)
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 111, in _get_module_details
    __import__(pkg_name)
  File &quot;&lt;frozen zipimport&gt;&quot;, line 241, in load_module
  File &quot;&lt;frozen zipimport&gt;&quot;, line 709, in _get_module_code
  File &quot;&lt;frozen zipimport&gt;&quot;, line 570, in _get_data
zipimport.ZipImportError: can&#39;t decompress data; zlib not available
Traceback (most recent call last):
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File &quot;/root/Python-3.9.0/Lib/runpy.py&quot;, line 87, in _run_code
    exec(code, run_globals)
  File &quot;/root/Python-3.9.0/Lib/ensurepip/__main__.py&quot;, line 5, in &lt;module&gt;
    sys.exit(ensurepip._main())
  File &quot;/root/Python-3.9.0/Lib/ensurepip/__init__.py&quot;, line 210, in _main
    return _bootstrap(
  File &quot;/root/Python-3.9.0/Lib/ensurepip/__init__.py&quot;, line 129, in _bootstrap
    return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
  File &quot;/root/Python-3.9.0/Lib/ensurepip/__init__.py&quot;, line 38, in _run_pip
    return subprocess.run([sys.executable, &quot;-c&quot;, code], check=True).returncode
  File &quot;/root/Python-3.9.0/Lib/subprocess.py&quot;, line 524, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command &#39;[&#39;/root/Python-3.9.0/python&#39;, &#39;-c&#39;, &#39;\nimport runpy\nimport sys\nsys.path = [\&#39;/tmp/tmpneerzwve/setuptools-49.2.1-py3-none-any.whl\&#39;, \&#39;/tmp/tmpneerzwve/pip-20.2.3-py2.py3-none-any.whl\&#39;] + sys.path\nsys.argv[1:] = [\&#39;install\&#39;, \&#39;--no-cache-dir\&#39;, \&#39;--no-index\&#39;, \&#39;--find-links\&#39;, \&#39;/tmp/tmpneerzwve\&#39;, \&#39;--root\&#39;, \&#39;/\&#39;, \&#39;--upgrade\&#39;, \&#39;setuptools\&#39;, \&#39;pip\&#39;]\nrunpy.run_module(&quot;pip&quot;, run_name=&quot;__main__&quot;, alter_sys=True)\n&#39;]&#39; returned non-zero exit status 1.
make: *** [install] 错误 1
$ 
</code></pre></div>

<p>这里缺少的是zlib-devel软件包。  </p>
<p>执行<code>make install</code>安装成功：</p>
<div class="highlight"><pre><span></span><code>$ make install
......
Looking in links: /tmp/tmpth6ntz0v
Processing /tmp/tmpth6ntz0v/setuptools-49.2.1-py3-none-any.whl
Processing /tmp/tmpth6ntz0v/pip-20.2.3-py2.py3-none-any.whl
Installing collected packages: setuptools, pip
Successfully installed pip-20.2.3 setuptools-49.2.1
$
</code></pre></div>

<p>打印python版本验证：</p>
<div class="highlight"><pre><span></span><code>$ python3 -V
Python 3.9.0
$ 
</code></pre></div>

<p>虽然python安装成功，也能运行了。如果之前的依赖项没有安装，或者没装全，之后用的时候还是会报错的。  </p>
<h3 id="zhu-ge-jie-jue-yi-lai-xiang-wen-ti"><a class="toclink" href="#zhu-ge-jie-jue-yi-lai-xiang-wen-ti">逐个解决依赖项问题</a></h3>
<p>如果预先没有安装依赖的开发包（都是以devel名称结尾的包），就会遇到问题。这时候只能重新编译安装。  </p>
<p>首先，要知道缺少了什么，把依赖项安装好。<br>
基本不需要再次configure，这步可以跳过或者暂时先跳过。<br>
安装了新的依赖项，再次make编译，查看最后的报告，确认问题是否解决了。如果没有，先configure后再make看看。<br>
上面make后的编译报告如果没有提示问题了，再make install安装之后就好了。  </p>
<p>如果是生产环境，configure配置和make编译只会操作用户文件，就是在源码包内进行操作，不会操作系统文件。<br>
最后的make install是安装，这时会覆盖所有的系统文件。这步应该是有风险的，我也没有在重要系统上实际这么操作过。<br>
这里应该考虑在一个新的目录中，重新安装一份，然后再做切换。<br>
或者更好的做法是先在实验环境中全部安装好，再用后面的移植方法，直接把安装后的文件搬过来。  </p>
<h4 id="pip-install-bao-cuo"><a class="toclink" href="#pip-install-bao-cuo">pip install 报错</a></h4>
<p>pip是很重要的工具，并且安装python的时候需要依赖项openssl-devel。<br>
如果没有准备依赖项就安装，现在pip工具就无法安装模块，因为需要建立ssl连接来下载。<br>
命令可以执行，打印了版本信息，但是无法更新pip版本：</p>
<div class="highlight"><pre><span></span><code>$ python3 -m pip install -U pip
WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by &#39;SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)&#39;: /simple/pip/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by &#39;SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)&#39;: /simple/pip/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by &#39;SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)&#39;: /simple/pip/
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by &#39;SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)&#39;: /simple/pip/
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by &#39;SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)&#39;: /simple/pip/
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host=&#39;pypi.org&#39;, port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)) - skipping
Requirement already up-to-date: pip in /usr/local/lib/python3.9/site-packages (20.2.3)
WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host=&#39;pypi.org&#39;, port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(&quot;Can&#39;t connect to HTTPS URL because the SSL module is not available.&quot;)) - skipping
$ 
</code></pre></div>

<p>安装好依赖项，从头开始再执行一遍：</p>
<div class="highlight"><pre><span></span><code>yum install openssl-devel
./configure --enable-optimizations
make
make install
</code></pre></div>

<p>直接make看报告，依然会提示问题：</p>
<div class="highlight"><pre><span></span><code>Could not build the ssl module!
</code></pre></div>

<p>先configure之后再make就好了。这次make的时间稍长，应该是又有不少东西支持了，需要编译或者重新编译。  </p>
<p>最后再验证一下：</p>
<div class="highlight"><pre><span></span><code>$ pip3 -V
pip <span class="m">20</span>.2.3 from /usr/local/lib/python3.9/site-packages/pip <span class="o">(</span>python <span class="m">3</span>.9<span class="o">)</span>
$ python3 -m pip install -U pip
Requirement already up-to-date: pip <span class="k">in</span> /usr/local/lib/python3.9/site-packages <span class="o">(</span><span class="m">20</span>.2.3<span class="o">)</span>
$
</code></pre></div>

<h4 id="python-shell-wu-fa-yi-dong-guang-biao"><a class="toclink" href="#python-shell-wu-fa-yi-dong-guang-biao">python shell 无法移动光标</a></h4>
<p>直接执行python命令，可以进入python shell，使用箭头移动光标会出现乱码：</p>
<div class="highlight"><pre><span></span><code>$ python3
Python 3.9.0 (default, Oct 12 2020, 15:54:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; ^[[B^[[B^[[B
</code></pre></div>

<p>这个是因为缺少readline的支持。在make的报告里能看到反应这个问题。<br>
对应的依赖项是readline-devel，安装后再编译安装：</p>
<div class="highlight"><pre><span></span><code>$ yum install readline-devel
$ make
$ make install
</code></pre></div>

<p>执行make后先看编译报告确认，此时已经不再报告readline的问题了。安装后再试一下确认。  </p>
<h4 id="que-shao-qi-ta-yi-lai-xiang"><a class="toclink" href="#que-shao-qi-ta-yi-lai-xiang">缺少其他依赖项</a></h4>
<p>之前make之后，还提示了缺少一堆依赖项，这些都不是必须的，有一些可能根本就没机会用上，或者是我目前还没遇到。<br>
但是碰到了就会报错。比如提示缺少_bz2，如果用到bz2模块就会报错：</p>
<div class="highlight"><pre><span></span><code>$ python3 -m bz2
Traceback (most recent call last):
  File &quot;/usr/local/lib/python3.9/runpy.py&quot;, line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File &quot;/usr/local/lib/python3.9/runpy.py&quot;, line 87, in _run_code
    exec(code, run_globals)
  File &quot;/usr/local/lib/python3.9/bz2.py&quot;, line 18, in &lt;module&gt;
    from _bz2 import BZ2Compressor, BZ2Decompressor
ModuleNotFoundError: No module named &#39;_bz2&#39;
$ 
</code></pre></div>

<p>这往往就算因为缺少了对应的devel开发包。安装上之后再重新跑一遍编译安装。<br>
这里是缺少bzip2-devel软件包，包含下面这些文件：</p>
<div class="highlight"><pre><span></span><code>$ rpm -lq bzip2-devel
/usr/include/bzlib.h
/usr/lib64/libbz2.so
/usr/share/doc/bzip2-devel-1.0.6
/usr/share/doc/bzip2-devel-1.0.6/manual.html
/usr/share/doc/bzip2-devel-1.0.6/manual.pdf
$ 
</code></pre></div>

<p>编译安装需要用到相关的.h文件或者.so文件，如果系统中找不到，就不支持对应的模块。  </p>
<p>编译报告：</p>
<div class="highlight"><pre><span></span><code>INFO: Could not locate ffi libs and/or headers

Python build finished successfully!
The necessary bits to build these optional modules were not found:
_bz2                  _dbm                  _gdbm
_lzma                 _sqlite3              _tkinter
_uuid
To find the necessary bits, look in setup.py in detect_modules() for the module&#39;s name.


The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  atexit                pwd
time


Failed to build these modules:
_ctypes
</code></pre></div>

<p>这里看到还有一些可选的模块找不到依赖项。按照下面的建议，可以去setup.py里去查查需要什么。看了也没完全看明白，基本没太大用处。  </p>
<p><strong>模块依赖的开发包：</strong>  </p>
<table>
<thead>
<tr>
<th align="left">可选模块</th>
<th align="left">软件包</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">_bz2</td>
<td align="left">bzip2-devel</td>
</tr>
<tr>
<td align="left">_dbm, _gdbm</td>
<td align="left">gdbm-devel</td>
</tr>
<tr>
<td align="left">_lzma</td>
<td align="left">xz-devel</td>
</tr>
<tr>
<td align="left">_sqlite3</td>
<td align="left">sqlite-devel</td>
</tr>
<tr>
<td align="left">_tkinter</td>
<td align="left">tcl-devel, tk-devel</td>
</tr>
<tr>
<td align="left">_uuid</td>
<td align="left">uuid-devel(没用)</td>
</tr>
<tr>
<td align="left">_ctypes</td>
<td align="left">libffi-devel</td>
</tr>
</tbody>
</table>
<p>补上上面这些依赖项目后，再make看下：</p>
<div class="highlight"><pre><span></span><code>The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  atexit                pwd
time


Failed to build these modules:
_uuid
</code></pre></div>

<p>有一个_uuid，原本是缺少依赖项。但是补上开发包后，变成编译失败了。<br>
直接按官方文档给的方法，安装完整依赖项，make的报告里一点问题没有。所以还有那么几个包没装全，不折腾了。  </p>
<h3 id="pip-pei-zhi"><a class="toclink" href="#pip-pei-zhi">pip 配置</a></h3>
<p>在pip安装完成后，先设置一下pypi源，使用国内镜像：</p>
<div class="highlight"><pre><span></span><code>pip3 config <span class="nb">set</span> global.index-url https://mirrors.aliyun.com/pypi/simple/
pip3 config <span class="nb">set</span> install.trusted-host mirrors.aliyun.com
</code></pre></div>

<p>然后再把pip更新到最新版本：</p>
<div class="highlight"><pre><span></span><code>python3 -m pip install -U pip
</code></pre></div>

<h3 id="yi-zhi"><a class="toclink" href="#yi-zhi">移植</a></h3>
<p>相同的操作系统，只需拷贝所有文件到另外一个机器即可。<br>
可以先在实验环境上折腾，安装好之后，把所有文件打包，再传到新的服务器上解压即可。依赖的开发包只是编译安装时需要的，移植运行的服务器不需要这些。<br>
默认的安装路径比较分散，用一个临时目录，配置--prefix选项（比如/usr/loca/python3.9），方便之后打包。  </p>
<p>完整的编译安装过程如下：</p>
<div class="highlight"><pre><span></span><code>wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
tar -zxvf Python-3.9.0.tgz
<span class="nb">cd</span> Python-3.9.0

yum install yum-utils
yum-builddep python3
yum downgrade kernel-headers-3.10.0-1127.18.2.el7

./configure --prefix<span class="o">=</span>/usr/local/python3.9
./configure --enable-optimizations --prefix<span class="o">=</span>/usr/local/python3.9
make
make <span class="nb">test</span>
make install
</code></pre></div>

<p>看一下程序包含的文件夹以及大小：</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /usr/local/python3.9/
$ du --max-depth<span class="o">=</span><span class="m">1</span> -h
15M     ./bin
229M    ./lib
<span class="m">1</span>.1M    ./include
20K     ./share
245M    .
$ 
</code></pre></div>

<p>打包所有文件：</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span> /usr/local/python3.9/
tar -czvf python-3.9.0.tgz *
</code></pre></div>

<p>这里进入到目录内，打包所有文件目录。一级目录没有隐藏文件和隐藏目录，用*号就可以了。<br>
这么做是故意不包括python3.9目录的。这样可以移植到新位置的/usr/local/目录中。  </p>
<p>将tar包传到新的服务器后，可以在指定的目录内解压：</p>
<div class="highlight"><pre><span></span><code>tar -tvzf python-3.9.0.tgz
tar -xvzf python-3.9.0.tgz -C /usr/local/ <span class="p">|</span> tee uninstall-python-3.9.0.log
</code></pre></div>

<p>先看一下压缩包中的内容，确认用的是相对路径。然后可以放心解压到指定的位置。<br>
当然也可以cd到要安装的位置，然后解压，这样就不需要-C参数了。<br>
这里选的安装路径内还有其他文件，所以新文件解压后会和之前的文件混在一起。最好把解压的所有文件的路径都记录下来，方便卸载。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>